/**
 * 
 */
package switchviz.core.view;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;

import org.jdom.Element;

import switchviz.graphic.GraphicEventListener;
import switchviz.graphic.GraphicFactory;
import switchviz.graphic.GraphicUtils;
import switchviz.graphic.GraphicsFrame;
import switchviz.graphic.gauge.DetailGaugeEventListener;
import switchviz.graphic.gauge.GaugeDetailed;
import switchviz.graphic.gauge.GaugeDialog;
import switchviz.graphic.gauge.IGauge;

/**
 *
 *
 */
public class ViewEventListener extends GraphicEventListener implements ActionListener
{
	private View _view = null;
	private IGauge[] _gaugearray = null;
	private int _rows = 0;
	private int _cols = 0;
	private int _selectedindex = -1;
	private boolean _doselect = false;
	private boolean _doremove = false;
	private float _saveGaseX = 0.0f;
	private float _saveGaseY = 0.0f;
	private float _saveGaseZ = -1.0f;
	private float _savePosX = 0.0f;
	private float _savePosY = 0.0f;
	private float _savePosZ = 2.5f;
	private float _savRotX = 0.0f;
	private float _savRotY = 0.0f;
	private GaugeDialog _gaugedialog = null;
	private LinkedList<GraphicsFrame> _detaillist = new LinkedList<GraphicsFrame>();
	private boolean _calcnotcon = false;
	
	private long _keytimer;
	
	public ViewEventListener(View view)
	{
		_view = view;
		initialize();
		this.setBGColor(_view.getDataModel().getBGColor());
	}
	
	public ViewEventListener()
	{
		super();
	}

	public void display(GLAutoDrawable drawable)
	{
		super.display(drawable);
		if (_view == null)
			return;
		GL gl = drawable.getGL();
		
		checkGrid();
		
		float height = 1.0f/_rows;
	    float width = 1.0f/_cols;
        
		gl.glTranslatef((-_cols*width)+width, (_rows*height)-height, 0.0f);
		gl.glScalef(width, height, Math.min(width, height));
		
		int gaugeposition = -1;
		for(int count = 0; count < _gaugearray.length; ++count)
		{
			if(!_view.getDataModel().isDisplayNotConnected() && !_gaugearray[count].isConnected())
			{	
				continue;
			}
			gaugeposition++;
			gl.glPushMatrix();
			Point pos = getGaugePosition(gaugeposition);
			gl.glTranslatef(2 * pos.x, -2 * pos.y, 0.0f);
				
			// print name
			gl.glTranslatef(0.0f, -0.9f, 0.0f);
			gl.glColor3f(1.0f, 1.0f, 1.0f);
			
			if(_gaugearray[count].getGaugeDataModel().isMultiplePerPort())
				GraphicUtils.drawString(gl, 8, GraphicUtils.ALIGN_CENTER, 0, _gaugearray[count].getGaugeDataModel().getName() + " @ " + _gaugearray[count].getGaugeDataModel().getPort());
			else
				GraphicUtils.drawString(gl, 8, GraphicUtils.ALIGN_CENTER, 0, _gaugearray[count].getGaugeDataModel().getName());
			
			gl.glTranslatef(0.0f, 0.9f, 0.0f);
			gl.glScalef(0.7f, 0.7f, 0.7f);
			rotateEachCell(gl);
			
			_gaugearray[count].draw(gl);

			gl.glPopMatrix();
		}
	}
	
	private void checkGrid()
	{
		if(!_view.getDataModel().isDisplayNotConnected())
		{
			if(_calcnotcon)
			{
				int enabledgauges = 0;
				for(IGauge gauge : _gaugearray)
				{
					if(gauge.isConnected()) enabledgauges++;
				}
				calculateGrid(enabledgauges);
				_calcnotcon = false;
			}
		}
		else
		{
			if(!_calcnotcon)
			{
				calculateGrid(_gaugearray.length);
				_calcnotcon = true;
			}
		}
	}
	
	private int getSelectedGaugeIndex(int posx, int posy)
	{
		int x = 0, y = 0, index = 0;
		x = posx / (_screenwidth / _cols);
		y = posy / (_screenheight / _rows);
		index = x + _cols * y;
		if(index > _gaugearray.length - 1)
			index = _gaugearray.length -1;
		
		if(!_calcnotcon)
		{
			List<Integer> enabledlist = new ArrayList<Integer>();
			for(int i = 0; i < _gaugearray.length; ++i)
			{
				if(_gaugearray[i].isConnected())
					enabledlist.add(i);
			}
			index = enabledlist.get(index);
		}
		return index;
	}
	
	private Point getGaugePosition(int num)
	{
		int x = 0, y = 0;
		y = num / _cols;
		x = num - y*_cols;
		return new Point(x, y);
	}
	
	public void mousePressed(MouseEvent evt) 
	{
		super.mousePressed(evt);
		((Component)evt.getSource()).setCursor(new Cursor(Cursor.MOVE_CURSOR));
		
		if(_doselect)
		{
			_selectedindex = getSelectedGaugeIndex(_mouseFixX, _mouseFixY);
			if(evt.getClickCount() > 1)
			{
				GaugeDetailed detailed = new GaugeDetailed(_gaugearray[_selectedindex].getVisibleSignals());
				String title = "Detail View of " + _gaugearray[_selectedindex].getGaugeDataModel().getName();
				if(_gaugearray[_selectedindex].getGaugeDataModel().isMultiplePerPort())
					title +=  " @ " + _gaugearray[_selectedindex].getGaugeDataModel().getPort();
				
				Element element = (Element)_gaugearray[_selectedindex].getElement().clone();
				
				IGauge newgauge = GraphicFactory.getInstance().getGauge(_gaugearray[_selectedindex].getGaugeDataModel().getType(), element);
				
				newgauge.getGaugeDataModel().setPort(_gaugearray[_selectedindex].getGaugeDataModel().getPort());
				newgauge.setSignals(_gaugearray[_selectedindex].getSignals());
				newgauge.setVisibleSignals(_gaugearray[_selectedindex].getVisibleSignals());
				
				evt.consume();
				
				
				GraphicsFrame gf = new GraphicsFrame(title, 30, new DetailGaugeEventListener(newgauge, detailed));
				_detaillist.add(gf);
				gf.setSize(300, 300);
				gf.setVisible(true);
				
				
				
				_selectedindex = -1;
				leaveSelMode();
				_doselect = false;
				_keytimer = System.currentTimeMillis()+100;
			}
			else if(evt.getButton() == MouseEvent.BUTTON3)
			{
				_gaugedialog = GaugeDialog.getInstance();
				
				_gaugedialog.setGauge(_gaugearray[_selectedindex]);
				_gaugedialog.setIndex(_selectedindex);

				_gaugedialog.addActionListener(this);
				
				
				_selectedindex = -1;
				leaveSelMode();
				_doselect = false;
				_keytimer = System.currentTimeMillis()+100;
			}
		}
		else if(_doremove)
		{
			if(_gaugearray.length < 1) return;
			_selectedindex = getSelectedGaugeIndex(_mouseFixX, _mouseFixY);
			if(evt.getClickCount() > 1)
			{
				IGauge[] temparray = new IGauge[_gaugearray.length - 1];
				int j = 0;
				for(int i = 0; i < _gaugearray.length; ++i)
				{
					if(i == _selectedindex) continue;

					temparray[j] = _gaugearray[i];
					++j;
				}
				_gaugearray = temparray;
				_view.setGaugeArray(_gaugearray);
			}
		}
	}
	
	public void closeDetailViews()
	{
		for(GraphicsFrame gf : _detaillist)
		{
			if(gf.isVisible())
			{
				gf.stopAnimator();
				gf.setVisible(false);
			}
		}
	}
	
	public void mouseDragged(MouseEvent evt) 
	{
		if(!_doselect && !_doremove)
			super.mouseDragged(evt);
	}
	
	public void mouseReleased(MouseEvent evt) 
	{
		super.mouseReleased(evt);
		if(_doselect && _selectedindex > -1)
		{
			int _cindex = getSelectedGaugeIndex(evt.getX(), evt.getY());
			IGauge tempgauge = _gaugearray[_cindex];
			_gaugearray[_cindex] = _gaugearray[_selectedindex];
			_gaugearray[_selectedindex] = tempgauge;
		}
	}

	
	private void initialize()
	{
		_gaugearray = _view.getGaugeArray();
		calculateGrid(_gaugearray.length);
	}
	
	private void calculateGrid(float num)
	{
		float fact = (float)Math.sqrt(num); 
		
		float temprows = fact - 1;
		float tempcols = fact;
		_rows = (int) (temprows + 0.5f);
		_cols = (int) (tempcols + 0.5f);
		
		if (_rows < 1) _rows = 1;
		if (_cols < 1) _cols = 1;
		
		while (_rows * _cols < num)
			_cols++;
	}
	
	private void setNeutralPosition()
	{
		_camGazeX = 0.0f;
		_camGazeY = 0.0f;
		_camGazeZ = -1.0f;
		_camPosX = 0.0f;
		_camPosY = 0.0f;
		_camPosZ = 2.4f;
		_cellRotX = 0.0f;
		_cellRotY = 0.0f;
	}
	
	private void leaveSelMode()
	{
		_camGazeX = _saveGaseX;
		_camGazeY = _saveGaseY;
		_camGazeZ = _saveGaseZ;
		_camPosX = _savePosX;
		_camPosY = _savePosY;
		_camPosZ = _savePosZ;
		_cellRotX = _savRotX;
		_cellRotY = _savRotY;
	}
	
	private void selModeAndSavePos()
	{
		_saveGaseX = _camGazeX;
		_saveGaseY = _camGazeY;
		_saveGaseZ = _camGazeZ;
		_savePosX = _camPosX;
		_savePosY = _camPosY;
		_savePosZ =  _camPosZ;
		_savRotX = _cellRotX;
		_savRotY = _cellRotY;
		setNeutralPosition();
	}

	public void init(GLAutoDrawable drawable)
	{
		super.init(drawable);
		if(_gaugearray == null) return;
		for(int i = 0; i < _gaugearray.length; ++i)
			_gaugearray[i].initialize(drawable.getGL());
	}

	public void keyPressed(KeyEvent evt) 
	{
		if(!_doselect && evt.getKeyChar() == 's' && _keytimer < System.currentTimeMillis())
		{
			selModeAndSavePos();
			_doselect = true;
		}
		else if(evt.getKeyChar() == 'c')
		{
			setNeutralPosition();
		}
		else if(!_doremove && evt.getKeyChar() == 'r')
		{
			selModeAndSavePos();
			_doremove = true;
		}
	}
	
	public void keyReleased(KeyEvent evt) 
	{
		if(_doselect && evt.getKeyChar() == 's')
		{
			_doselect = false;
			leaveSelMode();
		}
		else if(_doremove && evt.getKeyChar() == 'r')
		{
			_doremove = false;
			leaveSelMode();
		}
	}

	public void actionPerformed(ActionEvent evt) 
	{
		String command = evt.getActionCommand();
		if(command.equals(GaugeDialog.APPLY))
		{
			_gaugearray[_gaugedialog.getIndex()].setElement(_gaugedialog.getElement());
		}
		_gaugedialog.setVisible(false);
		_view.setGaugeArray(_gaugearray);
		leaveSelMode();
	}

}
